//
//  NetWorkTool.swift
//  NewTradmarkSerice
//
//  Created by hlt on 2023/3/22.
//

import UIKit
import Alamofire

typealias SuccessHandlerType = ([String:String]) -> Void
protocol Requestable{
    var paramersEncoder:ParameterEncoder{get}
    var baseURL: URL { get }
    var path: String { get }
    var parmeters:[String:String]  {get}
    var headers:[String: String]?{get}
    var method:HTTPMethod {get}
}

extension Requestable{
    var baseURL: URL {
        
        return URL.init(string: API.productBaseURl)!
    }
    
    
    var method:HTTPMethod{
        return .post
    }
    var paramersEncoder:ParameterEncoder{
        return  URLEncodedFormParameterEncoder(destination: .methodDependent)
    }
    var parmeters:[String:String]{
        return [String:String]() 
    }
    
    var headers:[String:String]?{
        var header = [String:String]()
        header["appName"] = "app"
        if UserInfo.shareInfo?.token.count  ?? 0  > 0{
            header["Authorization"] = UserInfo.shareInfo!.token
        }
        
       
        return  header
    }
}
let sessionManager: Session = {
  let configuration = URLSessionConfiguration.af.default
    
   configuration.timeoutIntervalForRequest = 30
  return Session(configuration: configuration)
}()


extension Requestable{
    @discardableResult
 func fetchData<Model:Codable>(_ compelte: @escaping (_ responseJson:Result<Model, NSError>) -> Void,showErrorHud:Bool = true) ->DataRequest{
        let dataRequest =  self.fetchData({ responseJson in
            switch responseJson{
            case .success(let json):
                let data =  try! json.rawData()
                let jsonCoder =  JSONDecoder()
                let model = try! jsonCoder.decode(Model.self, from: data)
                compelte(.success(model))
                break
                
            case .failure(let error):
                compelte(.failure(error))
                break
            }
        }, showErrorHud: showErrorHud)
        return dataRequest
    }

    
    @discardableResult
    func fetchData(_ complte: @escaping (_ responseJson:Result<JSON,NSError>) -> Void,showErrorHud:Bool = true) ->DataRequest{
        let url = baseURL.appendingPathComponent(path)
        let headers = HTTPHeaders(self.headers ?? [String:String]())
        var dic =  self.addCommonParameters(dic:self.parmeters,path: path)
        let signString = self.sortedParameters(dic, true, ParameterConstant.appKey).md5()
        dic["sign"] = signString
     
        let dataRequest = sessionManager.request(url, method: self.method,  parameters:dic, encoder:self.paramersEncoder,headers: headers).response {  response in
            switch response.result {
            case .success(let data):
                guard let responseData = data else{
                    testPrint("返回为空")
                    complte(.success(JSON.null))
                    return;
                }
                guard  let json = try? JSON.init(data: responseData) else{
                    testPrint("返回不是json")
                    let str = String.init(data: data!, encoding: .utf8)
                    complte(.failure(NSError(domain: "", code: 9999, userInfo: ["message":"返回不是json","describStr":str!])))
                    if(showErrorHud==true){
                        EasyProgressHud.showInfo(str!)
                    }
                    
                    return;
                }
                
              //  testPrint(json)
                guard  json["errorCode"].intValue == 200 else{
                    
                    let message = json["message"].string ?? "请求异常"
                    complte(.failure(NSError(domain: "", code: json["errorCode"].intValue, userInfo: ["message":message])))

                    if(showErrorHud==true){
                        EasyProgressHud.showInfo(message)
                       
                    }
                    return
                }
                if json["data"].exists() == true {
       
                    complte(.success(json["data"]))
                }else{
                    complte(.success(json))
                }

                testPrint("当前请求地址:\(url)\n请求参数:\(dic)\n返回结果:\(json)")
                break
                
                case .failure(let error):
                complte(.failure(error as NSError ))
                break
            }
          
        }

        return dataRequest
    }
 

    
}


extension Requestable{
    
    
    
    /// 字典key按升降序
    /// - Parameters:
    ///   - parmeters: 参数字典
    ///   - ascending: true升序
 private  func sortedParameters(_ parmeters:[String:String], _ ascending:Bool = true,_ appkey:String) -> String{
        var sortedParameters:[Dictionary<String, String>.Element]!
        if ascending == true{
            // 按照键的升序对参数进行排序
            sortedParameters = parmeters.sorted(by: { $0.key < $1.key })
        }else{
            sortedParameters = parmeters.sorted(by: { $0.key > $1.key })
        }
        
        

        // 将排序后的参数键值对转换为字符串
        let parameterString = sortedParameters.map { dic in
              let key = dic.key
            
            //同步php
              var newvalue = dic.value.urlEncode().replacingOccurrences(of: "+", with: "%2B")
             newvalue = newvalue.replacingOccurrences(of: "%20", with: "+")
            
            //对额外指定的字符进行编码
             newvalue =  newvalue.stringPercentEncoding(characters: " ?~/")
            
            return "\(key)=\(newvalue)"
        }.joined(separator: "&")
        
     let newParameterString = "\(parameterString)&appkey=\(ParameterConstant.appKey)"
        
        return newParameterString
    }
    ///拼接公共参数
    private func addCommonParameters(dic:[String:String],path:String) -> [String:String]{
       var newDic = [String:String]()
       newDic["hannel_id"] = ParameterConstant.hannel_id
       newDic["device_id"] = ParameterConstant.device_id
       newDic["hannel_id"] = ParameterConstant.hannel_id
        if(path == URLPathString.leavePhone){
            newDic["channel_id"] = ParameterConstant.channelID.message
        }else{
            newDic["channel_id"] = ParameterConstant.channelID.login
        }
        
       
       newDic["version"] = Application.appVersion
       newDic["system_os"] = "1"
       newDic["reg_source"] = "3"
       let timestamp = Int(Date().timeIntervalSince1970) * 1000
       newDic["timestamp"] = "\(timestamp)"
       let mergedDict = newDic.merging(dic) { (_, new) in
             new
       }
       
       return mergedDict
    }
    
}


